﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SlimDX;
using SlimDX.Direct3D9;

namespace Gype.UI.D3D9
{
    class RoundRectProvider
    {
        public RoundRectProvider(Device dev, Rendertarget9 target)
        {
            mDevice = dev;
            mTarget = target;
            mVertexShader = new ShaderCompiler<VertexShader>(dev, Shaders.RoundedRectangle, "VertexMain", "vs_3_0");
            mPixelShaderFill = new ShaderCompiler<PixelShader>(dev, Shaders.RoundedRectangle, "PixelMainFill", "ps_3_0");
            mPixelShaderDraw = new ShaderCompiler<PixelShader>(dev, Shaders.RoundedRectangle, "PixelMainDraw", "ps_3_0");

            mDescSize = mPixelShaderFill.ConstantTable["elemSize"];
            mDescSizeDraw = mPixelShaderDraw.ConstantTable["elemSize"];

            mDescMatrix = mVertexShader.ConstantTable["orthoProjMatrix"];

            mDescRect = mPixelShaderFill.ConstantTable["rectParams"];
            mDescRectDraw = mPixelShaderDraw.ConstantTable["rectParams"];

            mDescStroke = mPixelShaderDraw.ConstantTable["strokeWidth"];
            mBrushParam = mPixelShaderFill.ConstantTable["brushSampler"];

            mViewportParam = mVertexShader.ConstantTable["viewportSize"];
            mTransformParam = mVertexShader.ConstantTable["transformMatrix"]; 
        }

        public void Fill(Vector2 pos, Vector2 size, float radiusH, float radiusV, Brush brush)
        {
            brush.ApplyToShader(mPixelShaderFill, mBrushParam);
            var vertices = mTarget.CreateTriangleList(pos - new Vector2(2, 2), size + new Vector2(4, 4), new Color4(1, 1, 1, 1));

            mDevice.VertexShader = mVertexShader.Shader;
            mDevice.PixelShader = mPixelShaderFill.Shader;

            mVertexShader.SetValue(mDescMatrix, mTarget.OrthoMatrix);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);

            mPixelShaderFill.SetValue(mDescRect, new Vector2(radiusH, radiusV));
            mPixelShaderFill.SetValue(mDescSize, size + new Vector2(4, 4));

            mDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);

            mDevice.VertexShader = null;
            mDevice.PixelShader = null;
        }

        public void Draw(Vector2 pos, Vector2 size, float radiusH, float radiusV, Brush brush, float stroke)
        {
            brush.ApplyToShader(mPixelShaderFill, mBrushParam);
            var vertices = mTarget.CreateTriangleList(pos - new Vector2(2, 2), size + new Vector2(4, 4), new Color4(1, 1, 1, 1));

            mDevice.VertexShader = mVertexShader.Shader;
            mDevice.PixelShader = mPixelShaderDraw.Shader;

            mVertexShader.SetValue(mDescMatrix, mTarget.OrthoMatrix);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);

            mPixelShaderFill.SetValue(mDescRectDraw, new Vector2(radiusH, radiusV));
            mPixelShaderFill.SetValue(mDescSizeDraw, size + new Vector2(4, 4));
            mPixelShaderDraw.SetValue(mDescStroke, new Vector2(stroke, stroke / size.Y));

            mDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);

            mDevice.VertexShader = null;
            mDevice.PixelShader = null;
        }

        private Device mDevice;
        private Rendertarget9 mTarget;
        private ShaderCompiler<VertexShader> mVertexShader;
        private ShaderCompiler<PixelShader> mPixelShaderFill;
        private ShaderCompiler<PixelShader> mPixelShaderDraw;
        private ConstantDescription mDescSize;
        private ConstantDescription mDescSizeDraw;
        private ConstantDescription mDescMatrix;
        private ConstantDescription mDescRect;
        private ConstantDescription mDescRectDraw;
        private ConstantDescription mDescStroke;
        private ConstantDescription mBrushParam;
        private ConstantDescription mViewportParam;
        private ConstantDescription mTransformParam;
    }
}
